package com.xiyuan.smartutils.tools;

import com.xiyuan.smartutils.*;
import com.xiyuan.smartutils.crypto.AES;
import com.xiyuan.smartutils.crypto.Base64;
import com.xiyuan.smartutils.crypto.HEX;

import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.LinkedList;
import java.util.ListIterator;

/**
 * the description for class KeyImpl
 *
 * @author xiyuan-lgz 2025-03-04 @version v1.0.0 新建与整理
 */
@SuppressWarnings("all")
final class KeyImpl {
    private static final String D_SP = "=>:=>";
    private static final String DT_TIME = "yyyy-MM-dd hh:mm:ss";
    // "TUV4A3B3C1D0E1F1G9H9I4J0K6L0M1N3O1P3Q1RTW".getBytes()
    private static final byte[] FMT_ = new byte[]{
            84, 85, 86, 52, 65, 51, 66, 51, 67, 49,
            68, 48, 69, 49, 70, 49, 71, 57, 72, 57,
            73, 52, 74, 48, 75, 54, 76, 48, 77, 49,
            78, 51, 79, 49, 80, 51, 81, 49, 82, 84,
            87};
    
    public String createKey(long seconds, String extra_data) {
        int[] c = DateTimes.getCurrent();
        int y = c[0];
        int M = c[1];
        int d = c[2];
        int h = c[3];
        int m = c[4];
        String y4 = (y + "");
        String MM = (M < 10 ? "0" : "") + M;
        String dd = (d < 10 ? "0" : "") + d;
        String hh = (h < 10 ? "0" : "") + h;
        String mm = (m < 10 ? "0" : "") + m;
        
        
        LinkedList<Object> fmt = new LinkedList<>();
        LinkedList<Character> replace_slots = new LinkedList<>();
        for (int i = 0; i < FMT_.length; i++) {
            char ch = (char) FMT_[i];
            if ('a' <= ch && ch <= 'z' || 'A' <= ch && ch <= 'Z') {
                replace_slots.add(ch);
            }
            fmt.add(ch);
        }
        
        LinkedList<String> data = new LinkedList<>(Arrays.asList('Y' + y4, 'M' + MM, 'D' + dd, 'H' + hh, 'I' + mm));
        do {
            
            String slot_data = ((LinkedList<String>) Objects.shuffle(data)).pollFirst();
            char slot1 = ((LinkedList<Character>) Objects.shuffle(replace_slots)).pollFirst();
            ListIterator<Object> ot = fmt.listIterator();
            boolean slot = false;
            while (ot.hasNext()) {
                Object o = ot.next();
                if ((o instanceof Character) && (char) o == slot1) {
                    if (!slot) {
                        ot.set(slot_data);
                    }
                    else {
                        ot.remove();
                    }
                    slot = true;
                }
            }
            if (!slot) {
                fmt.add(0, slot_data);
            }
        }
        while (!data.isEmpty());
        
        String rd = Randoms.random(2, "1234567890abcdef");
        // 7e 89
        // rd = "7e";
        fmt.removeIf(o -> o instanceof Character && replace_slots.contains(o));
        fmt.add("-");
        fmt.add(rd);
        if (extra_data != null) {
            
            Array<String> array = new Array<String>(new String(FMT_).split(""))
                    .filter(r -> '0' <= r.charAt(0) && r.charAt(0) <= '9');
            array.push("-", y4.substring(2), MM, dd, hh, mm, "-", rd);
            String key = array.join("");
            fmt.add(D_SP);
            try {
                fmt.add(AES.encode(extra_data, key));
            }
            catch (Exception e) {
                throw new RuntimeException(e);
            }
        }
        
        Array<String> data_ = new Array<>(Lists.toString(fmt, "").split(""));
        // 插入过期码
        // 最大 99999999999999， （14 位数）
        String dr = "" + Math.min(Math.max(seconds, 0), 99999999999999L);
        if (dr.length() % 2 != 0) dr = "0" + dr;
        int l = dr.length() / 2;
        byte i1 = HEX.toBytes("" + rd.charAt(0))[0];
        byte i2 = HEX.toBytes("" + rd.charAt(1))[0];
        
        data_.splice(i1, 0, (l + dr.substring(0, l)).split(""));
        data_.splice(i2, 0, (l + dr.substring(l)).split(""));
        // 混淆
        Array<Byte> bytes = Array.from(data_.join("").getBytes());
        int idv = HEX.toBytes(rd)[0] * 2;
        for (int i = 0; i < bytes.length(); i++) {
            bytes.set(i, (byte) (bytes.get(i) + idv));
        }
        bytes.push(i2, i1);
        
        // 讲两个随机码倒序插入
        return Base64.encode(bytes.toArray());
    }
    
    public _KT_REAL_ readKey(String key) {
        try {
            
            String extraData = null;
            Array<Byte> _temp_data = Array.from(Base64.decode(key));
            int i2 = _temp_data.pop(), i1 = _temp_data.pop();
            if ((i2 < 0 || i2 > 15) || (i1 < 0 || i1 > 15)) {
                throw new Exception("invalid key");
            }
            
            String rd = "" + HEX.toString(i2).charAt(0) + HEX.toString(i1).charAt(0);
            int idv = HEX.toBytes(rd)[0] * 2;
            int len = _temp_data.length();
            for (int i = 0; i < len; i++) {
                _temp_data.set(i, (byte) (_temp_data.get(i) - idv));
            }
            // 读取请求时长 请求时长 数据分布 是rd 字符值倒序
            int t = i2;
            i2 = i1;
            i1 = t;
            String _d_data = new String(Arrays.convert(_temp_data.toArray()));
            
            //
            int e_data_idx = _d_data.indexOf(D_SP);
            extraData = e_data_idx == -1 ? null : _d_data.substring(e_data_idx + D_SP.length());
            if (e_data_idx != -1) {_d_data = _d_data.substring(0, e_data_idx);}
            Array<String> data = new Array<>(_d_data.split(""));
            String l_s_2 = data.get(i2);
            if ("1234567890".indexOf(l_s_2) == -1) {
                throw new Exception();
            }
            
            final int l = Integer.parseInt(l_s_2);
            Array<String> v2_a = data.splice(i2, l + 1);
            if (i2 > data.length()) {
                throw new Exception();
            }
            
            if (i1 > data.length()) {
                throw new Exception();
            }
            Array<String> v1_a = data.splice(i1, l + 1);
            
            v1_a.shift();
            v2_a.shift();
            String v1 = v1_a.join("");
            String v2 = v2_a.join("");
            int dr = 0;
            try {
                if (l > 0) {dr = Integer.parseInt(v1 + v2);}
            }
            catch (Exception e) {
                throw new Exception();
            }
            
            
            String y4 = null;
            String MM = null;
            String dd = null;
            String hh = null;
            String mm = null;
            Array<String> fmt = new Array<String>();
            String rad = "";
            for (int i = 0; i < data.length(); i++) {
                String ch = data.get(i);
                if ("Y".equals(ch)) {
                    y4 = data.get(++i) + data.get(++i) + data.get(++i) + data.get(++i);
                }
                else if ("M".equals(ch)) {
                    MM = data.get(++i) + data.get(++i);
                }
                else if ("D".equals(ch)) {
                    dd = data.get(++i) + data.get(++i);
                }
                else if ("H".equals(ch)) {
                    hh = data.get(++i) + data.get(++i);
                }
                else if ("I".equals(ch)) {
                    mm = data.get(++i) + data.get(++i);
                }
                else if ("-".equals(ch)) {
                    rad = data.get(++i) + data.get(++i);
                }
                else {
                    fmt.push(ch);
                }
            }
            String time = new Array<String>(y4, "-", MM, "-", dd, " ", hh, ":", mm, ":00").join("");
            Date begin = new SimpleDateFormat(DT_TIME).parse(time);
            Date endTime = new Date(begin.getTime() + (dr * 1000L));
            long diff = (long) Math.floor(((endTime.getTime() - new Date().getTime()) / 1000f));
            fmt.push("-", y4.substring(2), MM, dd, hh, mm, "-", rad);
            
            _KT_REAL_ info_ = new _KT_REAL_();
            info_.key = fmt.join("");
            _KT_REAL_ info = info_;
            info.setBeginTime(begin);
            info.setEndTime(endTime);
            info.setEnabled(diff > 0);
            info.setDiff(Math.abs(diff));
            info.setReq(dr);
            info.setData(extraData != null && !extraData.isEmpty() ? AES.decode(extraData, info_.key) : extraData);
            StringBuilder strb = new StringBuilder();
            for (int i = 0; i < FMT_.length; i++) {
                char ch = (char) FMT_[i];
                if ('0' <= ch && ch <= '9') {
                    strb.append(ch);
                }
            }
            if (info_.key.indexOf(strb.toString()) != 0) {
                throw new Exception();
            }
            return info_;
        }
        catch (RuntimeException e) {
            throw e;
        }
        catch (Exception e) {
            throw new IllegalArgumentException("invalid key", e);
        }
    }
    
    @SuppressWarnings("AlibabaAvoidStartWithDollarAndUnderLineNaming")
    public static class _KT_REAL_ extends KeyTools.KeyInfo {
        private String key;
        
        void setKey(String key) {
            this.key = key;
        }
        
        void setBeginTime(Date beginTime) {
            this.beginTime = beginTime;
        }
        
        protected void setEndTime(Date endTime) {
            this.endTime = endTime;
        }
        
        protected void setEnabled(boolean enabled) {
            this.enabled = enabled;
        }
        
        protected void setDiff(long diff) {
            this.diff = diff;
        }
        
        protected void setReq(int req) {
            this.req = req;
        }
        
        protected void setData(String data) {
            this.data = data;
        }
        
        public String getKey() {
            return key;
        }
    }
}
